package com.jorado.core.utility;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;


public abstract class DfaScanner {

    // BREAK，结束片段，并回到起始状态，最多可回退50个字符，退回的字符将重新读取
    // state = BREAK - 退回字符数
    // state = BREAK - 1 // 结束并退回1个字符，即不包含当前字符
    public static final int BREAK = -1;

    // BACKSPACE，结束片段，并回到起始状态，回退所有空白符，退回的字符将重新读取
    // state = BACKSPACE - 回退所有空白符
    // state = BACKSPACE - 1 // 结束并退回1个字符，并回退之前所有空白符
    public static final int BACKSPACE = -50;

    // PUSH，压栈，并回到指定状态，最多900个状态
    // state = PUSH - 压栈后回到状态数
    // state = PUSH - 4 // 压入第2个栈，压栈后回到状态4
    public static final int PUSH = -100;

    // POP，弹栈，并回到指定状态，栈空回到起始状态0，表示结束片段
    // state = POP - 弹栈后回到状态数 - EMPTY * 栈空回到状态数
    // state = POP - 4 - EMPTY * 5 // 弹栈后回到状态4，栈空回到状态5
    public static final int POP = -1000000;
    public static final int EMPTY = -POP;

    // ERROR，解析出错，抛出异常
    // state = ERROR - 错误码
    // state = ERROR - 1 // 出错，并返回错误码为1的异常信息。
    public static final int ERROR = -100000000;

    public List<com.jorado.core.utility.Token> scan(String charStream, int offset) throws ParseException {
        return scan(charStream, offset, false);
    }

    public List<com.jorado.core.utility.Token> scan(String charStream, int offset, boolean errorWithSource) throws ParseException {
        List<com.jorado.core.utility.Token> tokens = new ArrayList<com.jorado.core.utility.Token>();
        // 解析时状态 ----
        StringBuilder buffer = new StringBuilder(); // 缓存字符
        StringBuilder remain = new StringBuilder(); // 残存字符
        int pre = 0; // 上一状态
        int state = 0; // 当前状态
        char ch; // 当前字符

        // 逐字解析 ----
        int i = 0;
        int p = 0;
        for (; ; ) {
            if (remain.length() > 0) { // 先处理残存字符
                ch = remain.charAt(0);
                remain.deleteCharAt(0);
            } else { // 没有残存字符则读取字符流
                if (i >= charStream.length()) {
                    break;
                }
                ch = charStream.charAt(i++);
                offset++;
            }

            buffer.append(ch); // 将字符加入缓存
            state = next(state, ch); // 从状态机图中取下一状态
            if (state <= ERROR) {
                throw new ParseException("DFAScanner.state.error, error code: " + (ERROR - state) + (errorWithSource ? ", source: " + charStream : ""), offset - buffer.length());
            }
            if (state <= POP) {
                int n = -(state % POP);
                int e = (state - n) / POP - 1;
                if (p <= 0) {
                    throw new ParseException("DFAScanner.mismatch.stack" + (errorWithSource ? ", source: " + charStream : ""), offset - buffer.length());
                }
                p--;
                if (p == 0) {
                    state = e;
                    if (state == 0) {
                        state = BREAK;
                    }
                } else {
                    state = n;
                    continue;
                }
            } else if (state <= PUSH) {
                p++;
                state = PUSH - state;
                continue;
            }
            if (state <= BREAK) { // 负数表示接收状态
                int acceptLength;
                if (state <= BACKSPACE) {
                    acceptLength = buffer.length() + state - BACKSPACE;
                    if (acceptLength > 0) {
                        int space = 0;
                        for (int s = acceptLength - 1; s >= 0; s--) {
                            if (Character.isSpaceChar(buffer.charAt(s))) {
                                space++;
                            } else {
                                break;
                            }
                        }
                        acceptLength = acceptLength - space;
                    }
                } else {
                    acceptLength = buffer.length() + state - BREAK;
                }
                if (acceptLength < 0 || acceptLength > buffer.length())
                    throw new ParseException("DFAScanner.accepter.error" + (errorWithSource ? ", source: " + charStream : ""), offset - buffer.length());
                if (acceptLength != 0) {
                    String message = buffer.substring(0, acceptLength);
                    com.jorado.core.utility.Token token = new com.jorado.core.utility.Token(message, offset - buffer.length(), pre);
                    tokens.add(token);// 完成接收
                }
                if (acceptLength != buffer.length())
                    remain.insert(0, buffer.substring(acceptLength)); // 将未接收的缓存记入残存
                buffer.setLength(0); // 清空缓存
                state = 0; // 回归到初始状态
            }
            pre = state;
        }
        // 接收最后缓存中的内容
        if (buffer.length() > 0) {
            String message = buffer.toString();
            tokens.add(new Token(message, offset - message.length(), pre));
        }
        return tokens;
    }

    public abstract int next(int state, char ch);

}